/* Copyright (c) 2006 by M Aamir Maniar 
 * 
 * Permission is hereby granted, free of charge, to any person obtaining 
 * a copy of this software and associated documentation files (the 
 * "Software"), to deal in the Software without restriction, including 
 * without limitation the rights to use, copy, modify, merge, publish, 
 * distribute, sublicense, and/or sell copies of the Software, and to 
 * permit persons to whom the Software is furnished to do so, subject to 
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be 
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * 
 * */

namespace Generic.DataStructures
{
	using System;
	using System.Collections.Generic;
	using System.Text;
	using System.Collections;
	using System.Runtime.InteropServices;
	using System.Diagnostics;
	using Generic.Patterns;
    
	[Serializable]
	[ComVisible(true)]
	[DebuggerDisplay("Count = {Count}")]
	public abstract class ListBase<T> : IList<T>, ICloneable
	{
		#region Constructors
		List<T> _list;
		/// <summary>
		/// Initializes a new instance of the <see cref="ListBase&lt;T&gt;"/> class.
		/// </summary>
		protected ListBase()
		{
			_list = new List<T>();
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="ListBase&lt;T&gt;"/> class.
		/// </summary>
		/// <param name="capacity">The capacity.</param>
		protected ListBase(int capacity)
		{
			_list = new List<T>(capacity);
		}
		#endregion

		#region protected List<T> InnerList
		private List<T> InnerList
		{
			get
			{
				if (_list == null)
					_list = new List<T>();
				return _list;
			}
		}
		#endregion

		protected IList<T> List
		{
			get { return (IList<T>)this; }
		}

		#region public int Capacity
		[System.Runtime.InteropServices.ComVisible(false)]
		public int Capacity
		{
			get
			{
				return InnerList.Capacity;
			}
			set
			{
				InnerList.Capacity = value;
			}
		}
		#endregion

		public int Count
		{
			get { return List.Count; }
		}
	

		#region Protected

		protected virtual void OnSet(int index, T oldValue, T newValue)
		{
		}

		protected virtual void OnInsert(int index, T value)
		{
		}

		protected virtual void OnClear()
		{
		}

		protected virtual void OnRemove(int index, T value)
		{
		}

		protected virtual void OnValidate(T value)
		{
			if (value == null)
			{
				throw new ArgumentNullException("value");
			}
		}

		protected virtual void OnSetComplete(int index, T oldValue, T newValue)
		{
		}

		protected virtual void OnInsertComplete(int index, T value)
		{
		}

		protected virtual void OnClearComplete()
		{
		}

		protected virtual void OnRemoveComplete(int index, T value)
		{
		}

		#endregion

		#region IList<T> Members

		int IList<T>.IndexOf(T item)
		{
			return InnerList.IndexOf(item);
		}

		#region void Insert(int index, T item)
		void IList<T>.Insert(int index, T item)
		{
			if (index < 0 || index > InnerList.Count)
				throw new ArgumentOutOfRangeException();
			OnValidate(item);
			OnInsert(index, item);
			InnerList.Insert(index, item);
			try
			{
				OnInsertComplete(index, item);
			}
			catch
			{
				InnerList.RemoveAt(index);
				throw;
			}
		}

		#endregion

		#region public void RemoveAt(int index)
		public void RemoveAt(int index)
		{
			if (index < 0 || index >= InnerList.Count)
				throw new ArgumentOutOfRangeException();
			T temp = InnerList[index];
			OnValidate(temp);
			OnRemove(index, temp);
			InnerList.RemoveAt(index);
			try
			{
				OnRemoveComplete(index, temp);
			}
			catch
			{
				InnerList.Insert(index, temp);
				throw;
			}
		}
		#endregion

		T IList<T>.this[int index]
		{
			get
			{
				if (index < 0 || index >= InnerList.Count)
					throw new ArgumentOutOfRangeException();
				return InnerList[index];
			}
			set
			{
				if (index < 0 || index >= InnerList.Count)
					throw new ArgumentOutOfRangeException();
				OnValidate(value);
				T temp = InnerList[index];
				OnSet(index, temp, value);
				InnerList[index] = value;
				try
				{
					OnSetComplete(index, temp, value);
				}
				catch
				{
					InnerList[index] = temp;
					throw;
				}
			}
		}

		#endregion

		#region ICollection<T> Members

		void ICollection<T>.Add(T item)
		{
			OnValidate(item);
			OnInsert(InnerList.Count, item);
			InnerList.Add(item);
			int index = InnerList.Count - 1;
			try
			{
				OnInsertComplete(index, item);
			}
			catch
			{
				InnerList.RemoveAt(index);
				throw;
			}
		}

		void ICollection<T>.Clear()
		{
			OnClear();
			InnerList.Clear();
			OnClearComplete();
		}

		bool ICollection<T>.Contains(T item)
		{
			return InnerList.Contains(item);
		}

		void ICollection<T>.CopyTo(T[] array, int arrayIndex)
		{
			InnerList.CopyTo(array, arrayIndex);
		}

		int ICollection<T>.Count
		{
			get
			{
				return _list == null ? 0 : _list.Count;
			}
		}

		bool ICollection<T>.IsReadOnly
		{
			get 
			{
				return false;
			}
		}

		bool ICollection<T>.Remove(T item)
		{
			OnValidate(item);
			int index = InnerList.IndexOf(item);
			if (index < 0) 
				throw new ArgumentException("List does not contain item supplied");
			OnRemove(index, item);
			InnerList.RemoveAt(index);
			try
			{
				OnRemoveComplete(index, item);
				return true;
			}
			catch
			{
				InnerList.Insert(index, item);
				throw;
			}
		}

		#endregion

		#region IEnumerable<T> Members

		public IEnumerator<T> GetEnumerator()
		{
			for (int i = 0; i < InnerList.Count; i++)
			{
				yield return InnerList[i];
			}
		}

		#endregion

		#region IEnumerable Members

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		#endregion

		#region ICloneable Members

		object ICloneable.Clone()
		{
			return this.Clone();
		}

		public ListBase<T> Clone()
		{
			return new Prototype<ListBase<T>>(this).Clone();
		}

		#endregion
	}
}


